home *** CD-ROM | disk | FTP | other *** search
- char *ckxv = "XPR tty I/O, 5A(001), 23 Apr 92";
-
- /*
- * C K X T I O
- *
- * Terminal I/O functions for the Amiga External Protocol (XPR) version
- * of C Kermit.
- */
-
- #include "ckcdeb.h"
- #include "ckcker.h"
- #include "ckxker.h"
- #include "ckxtim.h"
-
- extern int local, what, spackets, fsecs, rpktl, spktl, bctu, numerrs, timeouts;
-
- extern long ffc, tsecs;
-
- extern long (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (),
- (*xfread) (), (*xsread) (), (*xchkabort) (void), (*xfnext) (), (*xffirst) (),
- (*xsflush) (void), (*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
- (*xsquery) (void), (*xchkmisc) (void), (*xsetserial)();
-
- int
- ttchk() {
- if (xsquery != NULL)
- return((*xsquery)());
- else
- return 0;
- }
-
- int
- ttclos(int ignore) {
- return 0;
- }
-
- int
- ttfluo(void) {
- return((*xsflush)());
- }
-
- int
- ttgmdm(void) {
- return -3;
- }
-
- long
- ttgspd(void) {
- int x;
-
- x = ((calld(xsetserial, -1L) >> 16) & 255);
- switch(x) {
- case 0:
- return(110L);
- case 1:
- return(300L);
- case 2:
- return(1200L);
- case 3:
- return(2400L);
- case 4:
- return(4800L);
- case 5:
- return(9600L);
- case 6:
- return(19200L);
- case 8:
- return(38400L);
- case 9:
- return(57600L);
- case 10:
- return(76800L);
- case 11:
- return(115200L);
- default:
- return -1;
- }
- }
-
- int
- tthang(void) {
- return 0;
- }
-
- void
- ttimoff(void) {
- }
-
- #ifdef MYREAD
-
- /* Private buffer for myread() and its companions. Not for use by anything
- * else. ttflui() is allowed to reset them to initial values. ttchk() is
- * allowed to read my_count.
- *
- * my_item is an index into mybuf[]. Increment it *before* reading mybuf[].
- *
- * A global parity mask variable could be useful too. We could use it to
- * let myread() strip the parity on its own, instead of stripping sign
- * bits as it does now.
- */
- #define MYBUFLEN 256
- static CHAR mybuf[MYBUFLEN];
-
- static int my_count = 0; /* Number of chars still in mybuf */
- static int my_item = -1; /* Last index read from mybuf[] */
-
- /* myread() -- Efficient read of one character from communications line.
- *
- * Uses a private buffer to minimize the number of expensive read() system
- * calls. Essentially performs the equivalent of read() of 1 character, which
- * is then returned. By reading all available input from the system buffers
- * to the private buffer in one chunk, and then working from this buffer, the
- * number of system calls is reduced in any case where more than one character
- * arrives during the processing of the previous chunk, for instance high
- * baud rates or network type connections where input arrives in packets.
- * If the time needed for a read() system call approaches the time for more
- * than one character to arrive, then this mechanism automatically compensates
- * for that by performing bigger read()s less frequently. If the system load
- * is high, the same mechanism compensates for that too.
- *
- * myread() is a macro that returns the next character from the buffer. If the
- * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error
- * returns.
- *
- * This should be efficient enough for any one-character-at-a-time loops.
- * For even better efficiency you might use memcpy()/bcopy() or such between
- * buffers (since they are often better optimized for copying), but it may not
- * be worth it if you have to take an extra pass over the buffer to strip
- * parity and check for CTRL-C anyway.
- *
- * Note that if you have been using myread() from another program module, you
- * may have some trouble accessing this macro version and the private variables
- * it uses. In that case, just add a function in this module, that invokes the
- * macro.
- */
- #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
-
- /* Specification: Push back up to one character onto myread()'s queue.
- *
- * This implementation: Push back characters into mybuf. At least one character
- * must have been read through myread() before myunrd() may be used. After
- * EOF or read error, again, myunrd() can not be used. Sometimes more than
- * one character can be pushed back, but only one character is guaranteed.
- * Since a previous myread() must have read its character out of mybuf[],
- * that guarantees that there is space for at least one character. If push
- * back was really needed after EOF, a small addition could provide that.
- *
- * myunrd() is currently not called from anywhere inside kermit...
- */
- #ifdef NOTUSED
- myunrd(ch) CHAR ch; {
- if (my_item >= 0) {
- mybuf[my_item--] = ch;
- ++my_count;
- }
- }
- #endif
-
- /* mygetbuf() -- Fill buffer for myread() and return first character.
- *
- * This function is what myread() uses when it can't get the next character
- * directly from its buffer. First, it calls a system dependent myfillbuf()
- * to read at least one new character into the buffer, and then it returns
- * the first character just as myread() would have done. This function also
- * is responsible for all error conditions that myread() can indicate.
- *
- * Returns: When OK => a positive character, 0 or greater.
- * When EOF => -2.
- * When error => -3, error code in errno.
- *
- * Older myread()s additionally returned -1 to indicate that there was nothing
- * to read, upon which the caller would call myread() again until it got
- * something. The new myread()/mygetbuf() always gets something. If it
- * doesn't, then make it do so! Any program that actually depends on the old
- * behaviour will break.
- *
- * The older version also used to return -2 both for EOF and other errors,
- * and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and
- * other errors now return different results, although Kermit currently never
- * checks to see which it was. It just disconnects in both cases.
- *
- * Kermit lets the user use the quit key to perform some special commands
- * during file transfer. This causes read(), and thus also mygetbuf(), to
- * finish without reading anything and return the EINTR error. This should
- * be checked by the caller. Mygetbuf() could retry the read() on EINTR,
- * but if there is nothing to read, this could delay Kermit's reaction to
- * the command, and make Kermit appear unresponsive.
- *
- * The debug() call should be removed for optimum performance.
- */
- int myfillbuf(void);
-
- int
- mygetbuf(void) {
- my_count = myfillbuf();
- debug(F101, "myfillbuf read", "", my_count);
- if (my_count <= 0)
- return(my_count < 0 ? -3 : -2);
- --my_count;
- return(255 & (int)mybuf[my_item = 0]);
- }
-
- /* myfillbuf():
- * System-dependent read() into mybuf[], as many characters as possible.
- *
- * Returns: OK => number of characters read, always more than zero.
- * EOF => 0
- * Error => -1, error code in errno.
- *
- * If there is input available in the system's buffers, all of it should be
- * read into mybuf[] and the function return immediately. If no input is
- * available, it should wait for a character to arrive, and return with that
- * one in mybuf[] as soon as possible. It may wait somewhat past the first
- * character, but be aware that any such delay lengthens the packet turnaround
- * time during kermit file transfers. Should never return with zero characters
- * unless EOF or irrecoverable read error.
- *
- * Correct functioning depends on the correct tty parameters being used.
- * Better control of current parameters is required than may have been the
- * case in older Kermit releases. For instance, O_NDELAY (or equivalent) can
- * no longer be sometimes off and sometimes on like it used to, unless a
- * special myfillbuf() is written to handle that. Otherwise the ordinary
- * myfillbuf()s may think they have come to EOF.
- *
- * If your system has a facility to directly perform the functioning of
- * myfillbuf(), then use it. If the system can tell you how many characters
- * are available in its buffers, then read that amount (but not less than 1).
- * If the system can return a special indication when you try to read without
- * anything to read, while allowing you to read all there is when there is
- * something, you may loop until there is something to read, but probably that
- * is not good for the system load.
- */
-
- /*
- * Following the example of the Unix code, I have chosen to write the XPR
- * version as follows: if the xpr_squery exists, then it is called.
- * If it does not exist, or returns 0, then we call xsread of 1 character
- * with a one-second timeout. Thus, we simply return 0 if no characters
- * arrive in one second, at which point we recheck our overall timeout.
- */
-
- int
- myfillbuf(void) {
- long avail;
- int x;
-
- if (xsquery)
- avail = (*xsquery)();
- if (!xsquery || avail == 0)
- avail = 1;
-
- if (avail > MYBUFLEN)
- avail = MYBUFLEN;
-
- return(calladd(xsread, mybuf, avail, 1000000L));
- }
-
-
- #endif /* MYREAD */
-
- /* T T F L U I -- Flush tty input buffer */
-
- int
- ttflui() {
-
- #ifdef MYREAD
- /*
- Flush internal MYREAD buffer *FIRST*, in all cases.
- */
- my_count = 0; /* Reset count to zero */
- my_item = -1; /* And buffer index to -1 */
- #endif /* MYREAD */
-
- if (xsflush)
- (void) (*xsflush)();
- return(0);
- }
-
- /*
- * T T I N L
- *
- * Return a line in the buffer pointed to by s from the serial line.
- * The line must end with eol and be no longer than max characters.
- * timeout is a timeout interval in seconds.
- *
- * Returns
- * > 0 Success--number of characters read
- * = 0 Shouldn't happen!
- * -1 Timeout
- * -2 Error of some other kind
- *
- * This version for XPR Kermit. We ignore negative returns from
- * the xpr_sread() function, preferring to take care of these
- * via the timeout mechanism.
- */
- int ttinl(CHAR *s, int max, int timeout, CHAR eol)
- {
- int x = 0;
- long i;
- struct timerequest *Timereq;
- unsigned mask;
- extern int parity;
-
- if (xchkmisc)
- (void) (*xchkmisc)();
- *s = '\0';
- mask = (parity ? 0177 : 0377);
- /*
- * Set up and post timer request for overall timeout.
- * As a compromise between correct and efficient, I only check
- * the overall timeout if a one-character read with a one second
- * timeout fails first.
- */
- if (!(Timereq = CreateTimer(UNIT_VBLANK)))
- return -1;
- Timereq->tr_time.tv_secs = timeout;
- Timereq->tr_time.tv_micro = 0;
- Timereq->tr_node.io_Command = TR_ADDREQUEST;
- SendIO((struct IORequest *) Timereq);
- #ifndef MYREAD
- /*
- * Willy Langeveld assures me that, since serial.device does its
- * own buffering, calling xsread once for each character isn't
- * going to take too long.
- *
- */
- for (x = 0; x < max; ) {
- if ((i = calladd(xsread, s, 1L, 1000000L)) < 0) {
- if (chkint() < 0) {
- x = -2;
- goto leave;
- }
- } else if (i == 1) {
- x++;
- if ((*s++ &= mask) == eol)
- break;
- } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
- x = -1; /* Flag timeout abort */
- goto leave;
- }
- }
- *s = '\0'; /* Normal termination */
- leave: /* Common cleanup code */
- AbortIO((struct IORequest *) Timereq);
- WaitIO((struct IORequest *) Timereq);
- DeleteTimer(Timereq);
- return(x);
- #else
- /*
- * Despite the comment above, the myread() macro significantly improves
- * performance on terminal emulators whose xpr_sread() is not as finely
- * tuned, apparently as VLT's. Term 3.n comes to mind...
- */
-
- for (x = 0; x < max; ) {
- if ((i = myread()) < -1) {
- /*
- * The following code deals with the case that
- * xsread() returns a negative value if the
- * user has clicked on the "Cancel File" or
- * "Cancel Batch" gadgets. However, we don't
- * want to abort receiving the current packet
- * in this case; calling chkint() now sets
- * the global cx and/or cz flags, but in the
- * case of a complete abort, chkint() returns
- * a negative value.
- */
- if (chkint() < 0) {
- x = -2; /* Error */
- goto leave;
- } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
- x = -1; /* Flag timeout abort */
- goto leave;
- }
- } else if (i >= 0) { /* Successful get of character */
- x++;
- *s = i;
- if ((*s++ &= mask) == eol)
- break;
- }
- }
- *s = '\0'; /* Normal termination */
- leave: /* Common cleanup code */
- AbortIO((struct IORequest *) Timereq);
- WaitIO((struct IORequest *) Timereq);
- DeleteTimer(Timereq);
- if (chkint() < 0)
- return -2;
- return(x);
- #endif /*MYREAD*/
- }
-
- int
- ttinc(int ttimo) {
- #ifndef MYREAD
- unsigned char ch;
- #else
- int n;
- #endif /*MYREAD*/
-
- #ifdef MYREAD
- n = myread();
- return (n < 0 ? n : n & 0377);
- #else
- if (calladd(xsread, &ch, 1, ttimo*1000000L) <= 0)
- return -1;
- return(ch);
- #endif /*MYREAD*/
- }
-
- int
- ttoc(char c) {
- if (callad(xswrite, &c, 1) == 0L)
- return 1;
- else
- return -1;
- }
-
- int
- ttol(CHAR *s, int n) {
- if (callad(xswrite, s, n) == 0L)
- return n;
- else
- return -1;
- }
-
- int
- ttopen(char *ttname, int *lcl, int modem, int timo) {
- return 0;
- }
-
- int
- ttpkt(long speed, int flow, int parity) {
- return 0;
- }
-
- int
- ttres(void) {
- return 0;
- }
-
- int
- ttscarr(int carrier) {
- return carrier;
- }
-
- int
- ttsndb(void) {
- return 0;
- }
-
- int
- ttsndlb(void) {
- return 0;
- }
-
- int
- ttsspd(int cps) {
- return 0;
- }
-
- int
- ttvt(long speed, int flow) {
- return 0;
- }
-
- int
- ttwmdm(int mdmsig, int timo) {
- return -3;
- }
-
- int
- ttxin(int n, CHAR *buf) {
- #ifdef MYREAD
- int c, i;
- #endif
-
- #ifdef MYREAD
- for (i = 0; i < n; i++) {
- c = myread();
- if (c < 0)
- return i;
- *buf++ = c & 0377;
- }
- return n;
- #else
- return(calladd(xsread, buf, n, 0L));
- #endif /*MYREAD*/
- }
-
- void
- ztime(char **s) {
- *s = "Ddd Mmm 00 00:00:00 0000\n"; /* Return dummy in asctime() format */
- }
-
- int
- msleep(int m) {
- struct timeval tv;
-
- tv.tv_secs = m/1000;
- tv.tv_micro = (m % 1000)*1000;
- return(MyDelay(&tv, 0L));
- }
-
- int
- sleep(int m) {
- return(msleep(1000*m));
- }
-
- static struct timeval now, elapsed;
-
- void
- rtimer(void) {
- GetSysTime(&now);
- }
-
- int
- gtimer(void) {
- GetSysTime(&elapsed);
- return((((1000000L*elapsed.tv_secs + elapsed.tv_micro) -
- (1000000L*now.tv_secs + now.tv_micro)) + 500000L)/1000000L);
- }
-
- int
- sysinit(void) {
- return 0;
- }
-
- int
- syscleanup(void) {
- return 0;
- }
-
- void
- connoi(void) {
- }
-
- int
- conoll(char *s) {
- return 0;
- }
-
- int
- conol(char *s) {
- return 0;
- }
-
- int
- conoc(char c) {
- return 1;
- }
-
- static int oldtyp = 0, olderrs = -1, oldlen = -1, oldffc = 0L, oldtimes = -1;
-
- char * /* Convert seconds to hh:mm:ss */
- hhmmss(long x)
- {
- static char buf[10];
- long s, h, m;
- h = x / 3600L; /* Hours */
- x = x % 3600L;
- m = x / 60L; /* Minutes */
- s = x % 60L; /* Seconds */
- if (x > -1L)
- sprintf(buf,"%02ld:%02ld:%02ld",h,m,s);
- else buf[0] = '\0';
- return((char *)buf);
- }
-
- /*
- * S C R E E N
- *
- * Display status on the screen. This version is the go-between from
- * what C Kermit needs and what XPR provides.
- */
- void
- screen(int f, char c, long n, char *s) {
- static struct XPR_UPDATE update;
- static char string[51], time1[15], time2[15];
- static long fsiz = -1L; /* Copy of file size */
- static long fcnt = 0L; /* File count */
- static long fbyt = 0L; /* Total file bytes */
- static char fn[257]; /* Local copy of file name */
-
- update.xpru_updatemask = 0;
- debug(F101,"screen f = ","",f); /* Handle our function code */
- if (n) debug(F101, "screen n = ", "", n);
- if (s) debug(F110, "screen s = ", s, n);
- switch(f) {
- case SCR_FN:
- if (what == W_SEND)
- sprintf(string, "Sending: %s", s);
- else
- sprintf(string, "Receiving: %s", s);
- update.xpru_filename = string;
- update.xpru_updatemask = XPRU_FILENAME;
- fsiz = -1L; /* Invalidate file size */
- strncpy(fn, s, 256);
- break;
- case SCR_AN:
- if (what == W_SEND)
- sprintf(string, "Sending: %s as %s", fn, s);
- else
- sprintf(string, "Receiving: %s as %s", fn, s);
- update.xpru_filename = string;
- update.xpru_updatemask = XPRU_FILENAME;
- break;
- case SCR_FS:
- fsiz = update.xpru_filesize = n;
- update.xpru_updatemask = XPRU_FILESIZE;
- break;
- case SCR_ST:
- switch (c) { /* Print new status message */
- case ST_OK: /* Transfer OK */
- fcnt++; /* Count this file */
- if (ffc > 0) /* For some reason ffc is off by 1 */
- fbyt += ffc - 1L; /* Count its bytes */
- strcpy(string, "Transfer OK");
- break;
- case ST_DISC:
- strcpy(string, "File discarded");
- break;
- case ST_INT:
- strcpy(string, "Transfer interrupted");
- break;
- case ST_SKIP:
- strcpy(string, "File skipped");
- break;
- case ST_ERR:
- sprintf(string, "%.50s", s);
- break;
- case ST_REFU:
- strcpy(string, "File refused");
- break;
- case ST_INC:
- strcpy(string, "Incompletely received");
- break;
- default:
- strcpy(string, "screen() called with bad status");
- break;
- }
- if (c == ST_OK) {
- update.xpru_updatemask = XPRU_MSG;
- update.xpru_msg = string;
- } else {
- update.xpru_updatemask = XPRU_ERRORMSG;
- update.xpru_errormsg = string;
- }
- break;
- case SCR_PN:
- update.xpru_blocks = n;
- update.xpru_updatemask = XPRU_BLOCKS;
- break;
- case SCR_PT:
- /*
- * Following the Unix version, we check everything and only
- * update what's actually changed since last time. The intent
- * is to prevent the screen updates from slowing the file
- * transfers.
- */
- update.xpru_updatemask = 0;
- if (spackets < 5) {
- switch (bctu) {
- case 1:
- update.xpru_blockcheck = "Sum-6";
- break;
- case 2:
- update.xpru_blockcheck = "Sum-12";
- break;
- case 3:
- update.xpru_blockcheck = "CRC-16";
- break;
- }
- update.xpru_updatemask |= XPRU_BLOCKCHECK;
- }
- if ((update.xpru_blocksize = (what == W_RECV) ? rpktl + 1 : spktl +
- 1) != oldlen) {
- update.xpru_updatemask |= XPRU_BLOCKSIZE;
- oldlen = update.xpru_blocksize;
- }
- update.xpru_blocks = spackets;
- update.xpru_updatemask |= XPRU_BLOCKS;
- if (c != oldtyp && c != 'Y' && c != 'N' && c != '%') {
- oldtyp = update.xpru_packettype = c;
- update.xpru_updatemask |= XPRU_PACKETTYPE;
- }
- if (numerrs != olderrs) {
- olderrs = update.xpru_errors = numerrs;
- update.xpru_updatemask |= XPRU_ERRORS;
- }
- if (ffc != oldffc) {
- oldffc = update.xpru_bytes = ffc;
- update.xpru_updatemask |= XPRU_BYTES;
- }
- switch (c) { /* Now handle specific packet types */
- long x, y;
- case 'S': /* Beginning of transfer */
- fcnt = fbyt = 0L; /* Clear counters */
- break;
- case 'D': /* Data packet */
- /* fsecs is the time from gtimer() this file started at */
- y = ((unsigned) gtimer() - fsecs); /* Secs so far */
- strcpy(time1, hhmmss(y));
- update.xpru_elapsedtime = time1;
- update.xpru_updatemask |= XPRU_ELAPSEDTIME;
- if (y > 0) {
- update.xpru_datarate = ((10L * ffc)/y)/10L;
- update.xpru_updatemask |= XPRU_DATARATE;
- }
- if (y > 0L && fsiz > 0L && ffc > 0L) { /* Update expected time so on */
- x = (y*fsiz)/ffc;
- strcpy(time2, hhmmss(x));
- update.xpru_expecttime = time2;
- update.xpru_updatemask |= XPRU_EXPECTTIME;
- }
- break;
- case 'E': /* Error packet */
- if (*s) { /* Print its data field */
- update.xpru_errormsg = s;
- update.xpru_updatemask |= XPRU_ERRORMSG;
- }
- fcnt = fbyt = 0; /* No bytes for this file */
- break;
- case 'Q':
- update.xpru_errormsg = "Damaged packet";
- update.xpru_updatemask |= XPRU_ERRORMSG;
- break;
- case 'T':
- update.xpru_errormsg = "Timeout";
- update.xpru_updatemask |= XPRU_ERRORMSG;
- if ((update.xpru_timeouts = timeouts) != oldtimes) {
- update.xpru_updatemask |= XPRU_TIMEOUTS;
- oldtimes = timeouts;
- }
- break;
- default:
- break;
- }
- break;
- case SCR_TC:
- if (tsecs > 0)
- sprintf(string, "Files: %ld, Total Bytes: %ld, %ld cps",
- fcnt, fbyt, ((fbyt * 10L) / (long) tsecs) / 10L);
- else
- sprintf(string, "Files: %ld, Total Bytes: %ld", fcnt, fbyt);
- update.xpru_msg = string;
- update.xpru_updatemask = XPRU_MSG;
- break;
- case SCR_EM:
- update.xpru_errormsg = s;
- update.xpru_updatemask = XPRU_ERRORMSG;
- break;
- case SCR_QE: /* Quantity equals */
- case SCR_TU: /* Undelmited text */
- case SCR_TN: /* Text delimited at start */
- case SCR_TZ: /* Text delimited at end */
- break;
- case SCR_XD: /* X packet data */
- update.xpru_filename = s;
- update.xpru_updatemask = XPRU_FILENAME;
- break;
- case SCR_CW: /* Close window */
- oldtyp = 0; /* Reset these counters for next time */
- olderrs = oldtimes = oldlen = -1;
- oldffc = 0;
- break;
- default:
- break;
- }
- if (update.xpru_updatemask) (void) calla(xupdate, &update);
- return;
- }
-
- /*
- * This is the XPR Kermit version of chkint. We allow multiple levels
- * of interrupt, if available.
- */
- int
- chkint(void) { /* Check for console interrupts. */
- int x;
- extern int cxseen, czseen;
-
- x = (*xchkabort)();
- switch (x) {
- case 0: /* No abort pending */
- return 0;
- case 1: /* Abort file only. */
- screen(SCR_TN,0,0l,"Cancelling File ");
- cxseen = 1;
- break;
- case 2: /* Abort file and batch. */
- screen(SCR_TN,0,0l,"Cancelling Batch ");
- czseen = 1;
- break;
- case -1: /* Emergency escape -- kill all */
- return -1;
- default:
- ;
- }
- return 1;
- }
-
- void
- intmsg(long n) {
- screen(SCR_TN, 0, 0L, "Interrupt using mouse or keyboard");
- }
-
- void
- ermsg(msg) char *msg; { /* Print error message */
- if (local)
- screen(SCR_EM,0,0L,msg);
- tlog(F110,"Protocol Error:",msg,0L);
- }
-
- void
- fatal(char *msg) {
- if (local)
- screen(SCR_EM,0,0L,msg);
- tlog(F110,"Fatal Error:",msg,0L);
- }
-
- void
- doclean(void) {
- }
-
- int
- psuspend(int x) {
- return 0;
- }
-